package wci.frontend.pascal.parsers;

import java.util.ArrayList;
import java.util.EnumSet;

import wci.frontend.*;
import wci.frontend.pascal.*;
import wci.intermediate.*;
import wci.intermediate.symtabimpl.*;

import static wci.frontend.pascal.PascalTokenType.*;
import static wci.frontend.pascal.PascalErrorCode.*;
import static wci.intermediate.symtabimpl.SymTabKeyImpl.*;
import static wci.intermediate.symtabimpl.DefinitionImpl.*;
import static wci.intermediate.typeimpl.TypeFormImpl.*;
import static wci.intermediate.typeimpl.TypeKeyImpl.*;

/**
 * <h1>VariableDeclarationsParser</h1>
 * <p>解析变量申明</p>
 * <p>Copyright (c) 2009 by Ronald Mak</p>
 * <p>For instructional purposes only.  No warranties.</p>
 */
public class VariableDeclarationsParser extends DeclarationsParser
{
	// 标识符怎么定义的？同是变量申明，上下文不一样，定义不一样
    private Definition definition;  
    public VariableDeclarationsParser(PascalParserTD parent)
    {
        super(parent);
    }

    /**
     * 设置此申明的定义
     * @param definition the definition to set.
     */
    protected void setDefinition(Definition definition)
    {
        this.definition = definition;
    }

    // 变量申明的同步集
    static final EnumSet<PascalTokenType> IDENTIFIER_SET =
        DeclarationsParser.VAR_START_SET.clone();
    static {
        IDENTIFIER_SET.add(IDENTIFIER);
        IDENTIFIER_SET.add(END);
        IDENTIFIER_SET.add(SEMICOLON);
    }

    // 下一个定义或申明的同步集
    static final EnumSet<PascalTokenType> NEXT_START_SET =
        DeclarationsParser.ROUTINE_START_SET.clone();
    static {
        NEXT_START_SET.add(IDENTIFIER);
        NEXT_START_SET.add(SEMICOLON);
    }

    public void parse(Token token)
        throws Exception
    {
        token = synchronize(IDENTIFIER_SET);

        // 遍历由分号分割的一系列变量申明
        while (token.getType() == IDENTIFIER) {

            //解析每一个子表标识申明，比如 a,b,c : int
            parseIdentifierSublist(token);

            token = currentToken();
            TokenType tokenType = token.getType();

            // 一个定义由分号结束
            if (tokenType == SEMICOLON) {
                while (token.getType() == SEMICOLON) {
                    token = nextToken();  // consume the ;
                }
            }else if (NEXT_START_SET.contains(tokenType)) {
            	//没有分号便开始下一个了。
                errorHandler.flag(token, MISSING_SEMICOLON, this);
            }

            token = synchronize(IDENTIFIER_SET);
        }
    }

    // 子表标识同步集，这里a,b,c: int 中的a,b,c算作子表
    static final EnumSet<PascalTokenType> IDENTIFIER_START_SET =
        EnumSet.of(IDENTIFIER, COMMA);

    // 标识符后的同步集
    private static final EnumSet<PascalTokenType> IDENTIFIER_FOLLOW_SET =
        EnumSet.of(COLON, SEMICOLON);
    static {
        IDENTIFIER_FOLLOW_SET.addAll(DeclarationsParser.VAR_START_SET);
    }

    // 逗号的同步集
    private static final EnumSet<PascalTokenType> COMMA_SET =
        EnumSet.of(COMMA, COLON, IDENTIFIER, SEMICOLON);

    /**
     * 解析标识符子表及类型说明
     * @param token the current token.
     * @return 一个申明中的子表标识符列表
     * @throws Exception
     */
    protected ArrayList<SymTabEntry> parseIdentifierSublist(Token token)
        throws Exception
    {
        ArrayList<SymTabEntry> sublist = new ArrayList<SymTabEntry>();

        do {
            token = synchronize(IDENTIFIER_START_SET);
            SymTabEntry id = parseIdentifier(token);

            if (id != null) {
                sublist.add(id);
            }

            token = synchronize(COMMA_SET);
            TokenType tokenType = token.getType();

            // 找逗号
            if (tokenType == COMMA) {
                token = nextToken(); //有逗号吞掉以便下一个

                if (IDENTIFIER_FOLLOW_SET.contains(token.getType())) {
                    errorHandler.flag(token, MISSING_IDENTIFIER, this);
                }
            }else if (IDENTIFIER_START_SET.contains(tokenType)) {
                errorHandler.flag(token, MISSING_COMMA, this);
            }
        } while (!IDENTIFIER_FOLLOW_SET.contains(token.getType()));

        //冒号后面的类型
        TypeSpec type = parseTypeSpec(token);

        //将子表中的每个变量的类型设置上，比如a,b,c:int，先解析了a,b,c，然后解析了int类型
        //那么这儿就会给a,b,c设置上int类型
        for (SymTabEntry variableId : sublist) {
            variableId.setTypeSpec(type);
        }

        return sublist;
    }

    /**
     * 解析标识符
     * @param token
     * @return 对应符号表项
     * @throws Exception
     */
    private SymTabEntry parseIdentifier(Token token)
        throws Exception
    {
        SymTabEntry id = null;

        if (token.getType() == IDENTIFIER) {
            String name = token.getText().toLowerCase();
            id = symTabStack.lookupLocal(name);

            //申明必须得没有，否则重定义了
            if (id == null) {
                id = symTabStack.enterLocal(name);
                id.setDefinition(definition);
                id.appendLineNumber(token.getLineNumber());
            }
            else {
                errorHandler.flag(token, IDENTIFIER_REDEFINED, this);
            }

            token = nextToken(); 
        }
        else {
            errorHandler.flag(token, MISSING_IDENTIFIER, this);
        }

        return id;
    }

    // 类型冒号处的同步集
    private static final EnumSet<PascalTokenType> COLON_SET =
        EnumSet.of(COLON, SEMICOLON);

    /**
     * 解析变量申明里的类型
     * @param token 当前token
     * @return 类型说明
     * @throws Exception
     */
    protected TypeSpec parseTypeSpec(Token token)
        throws Exception
    {
        // 同步在:处
        token = synchronize(COLON_SET);
        if (token.getType() == COLON) {
            token = nextToken(); // 吞掉 :
        }
        else {
            errorHandler.flag(token, MISSING_COLON, this);
        }

        // 解析类型说明
        TypeSpecificationParser typeSpecificationParser =
            new TypeSpecificationParser(this);
        TypeSpec type = typeSpecificationParser.parse(token);

        return type;
    }
}
